package com.jt.www.job.issue;

import com.jt.www.common.service.JobQueryListService;
import com.jt.www.dao.mapper.issue.mapper.IssuePolicyLogEntityMapper;
import com.jt.www.enums.issue.PolicyEnum;
import com.jt.www.model.issue.entity.IssuePolicyLogEntity;
import com.jt.www.model.pay.ResBindDetailQo;
import com.jt.www.model.pay.ResBindQo;
import com.jt.www.model.reps.GenericListResponse;
import com.jt.www.remote.DexClient;
import com.jt.www.remote.ins.InsClient;
import com.jt.www.util.DateUtils;
import com.jt.www.util.RedisUtil;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.util.StringUtil;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * 云南凌晨处理失败的电子发票
 *
 * @author xq.wu03
 * @create 2019-10-12 10:39
 */
@Component
@EnableScheduling
public class TimingCheckFailInvoiceTask implements SchedulingConfigurer {

    public static final Logger log = LoggerFactory.getLogger(TimingCheckFailInvoiceTask.class);
    /**
     * 单个服务器出单查询缓存失效时间 因不同的定时任务决定
     */
    private static final long DOWN_INVOICE_TIME_OUT = 80L;
    /**
     * 检查下载发票的任务 缓存key
     */
    private static final String DOWN_FAIL_INVOICE_LOCK_KEY = "EDU_FAIL_INVOICE";
    @Autowired
    IssuePolicyLogEntityMapper issuePolicyLogEntityMapper;
    @Autowired
    JobQueryListService jobQueryListService;
    @Autowired
    InsClient insClient;
    @Autowired
    DexClient dexClient;
    //  任务开关
    @Value("${jtpf.failinvoice.open}")
    private int checkOpen;
    // 任务执行周期
    @Value("${jtpf.failinvoice.cron}")
    private String cron;// 每天半夜12点30分执行一次
    //发送电子发票最小失败次数
    @Value("${jtpf.failinvoice.minTimes}")
    private String minTimes;
    //发送电子发票最大失败次数
    @Value("${jtpf.failinvoice.maxTimes}")
    private String maxTimes;//

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        if (checkOpen != 1) {
            return;
        }
        if (RedisUtil.setLock(DOWN_FAIL_INVOICE_LOCK_KEY, "1", DOWN_INVOICE_TIME_OUT)) {
            Runnable task0 = () -> checkFailInvoice();
            Trigger trigger0 = triggerContext -> new CronTrigger(cron).nextExecutionTime(triggerContext);
            scheduledTaskRegistrar.addTriggerTask(task0, trigger0);
        }
    }


    private void checkFailInvoice() {
        String currentTime = DateUtils.getCurrentTime();
        log.info(currentTime + "---CheckFailInvoice start,检查失败电子发票开始---");
        List<IssuePolicyLogEntity> failInvoiceList = queryFailInvoice();
        createInvoice(failInvoiceList);
        failInvoiceList = checkDownYNFJInvoice();
        downAndBindYNFJ(failInvoiceList);
        //查询实责校责下载电子发票的单子
        failInvoiceList = checkDownSZANDXZInvoice();
        downAndBindSZANDXZ(failInvoiceList);
        //查询学责生成发票失败的记录
        failInvoiceList = checkXZInvoice();
        createInvoiceXZ(failInvoiceList);
        //查询学责生成成功，但是下载失败的记录
        failInvoiceList = checkDownInvoice();
        downAndBind(failInvoiceList);
        log.info(currentTime + "---CheckFailInvoice end,检查失败电子发票结束---");
    }

    /**
     * 学责下载电子发票
     *
     * @param issuePolicyLogEntities
     */
    private void downAndBind(List<IssuePolicyLogEntity> issuePolicyLogEntities) {

        if (issuePolicyLogEntities != null && issuePolicyLogEntities.size() > 0) {
            for (IssuePolicyLogEntity t : issuePolicyLogEntities) {
                int times = t.getTimes() + 1;
                log.info(DateUtils.getCurrentTime() + "job调用数据交换中心下载发票开始，入参：" + t.getDownParam());
                String seqNo = Long.toString(Math.abs(new Random().nextLong()));
                ResponseEntity<String> responseEntity = null;
                try {
                    responseEntity = dexClient.text("edu", "20190515013", "1.1", seqNo, t.getDownParam());
                    log.info(DateUtils.getCurrentTime() + "job调用数据交换中心下载发票结束，回参：" + responseEntity.getStatusCodeValue() + "," + responseEntity.getBody());
                    // 请求200，继续执行
                    if (responseEntity.getStatusCodeValue() != 200) {
                        log.error("请求下载电子发票失败");
                        t.setStatus("6");
                        t.setTimes(times);
                        issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                    } else {
                        String ebody = responseEntity.getBody();
                        Document doc = DocumentHelper.parseText(ebody);
                        Element ebodyElement = doc.getRootElement();
                        String code = ebodyElement.element("code").getStringValue();
                        if ("0000".equals(code)) {
                            String eInvoiceId = ebodyElement.element("data").getStringValue();
                            t.setStatus("2");
                            t.setEInvoiceId(eInvoiceId);
                            t.setTimes(times);
                            bindInvoice(t.getApplicationFormCode(), eInvoiceId, t);
                        } else {
                            t.setStatus("6");
                            t.setTimes(times);
                            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("请求下载电子发票失败");
                    t.setStatus("6");
                    t.setTimes(times);
                    issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                }
            }
        }
    }


    private List<IssuePolicyLogEntity> checkXZInvoice() {
        Weekend<IssuePolicyLogEntity> weekend = Weekend.of(IssuePolicyLogEntity.class);
        WeekendCriteria<IssuePolicyLogEntity, Object> criteria = weekend.weekendCriteria();
        List<String> statusList = new ArrayList<String>();
        statusList.add("1");// 没有生成发票，
        statusList.add("7");// 生成发票失败的
        criteria.andIn(IssuePolicyLogEntity::getStatus, statusList);
        criteria.andEqualTo(IssuePolicyLogEntity::getType, "3");
        criteria.andEqualTo(IssuePolicyLogEntity::getProCode, "19PR403423");//学责
        criteria.andIsNull("eInvoiceId");
        criteria.andBetween(IssuePolicyLogEntity::getTimes, minTimes, maxTimes);
        return jobQueryListService.getJobProcessIssuePolicyLogList(weekend);
    }

    private void createInvoiceXZ(List<IssuePolicyLogEntity> issuePolicyLogEntities) {
        if (issuePolicyLogEntities != null && issuePolicyLogEntities.size() > 0) {

            for (IssuePolicyLogEntity t : issuePolicyLogEntities) {
                int times = t.getTimes() + 1;
                // 只有学责，云南非九  需要生成发票
                String proCode = t.getProCode();
                //String mainType = t.getMainType();
                //if("1".equals(proCode) && "0".equals(mainType)){
                if ("19PR403423".equals(proCode)) {//学责
                    try {
                        // 生成发票
                        // 调接口  生成发票
                        log.info(DateUtils.getCurrentTime() + "job调用学责生成发票接口，入参" + t.getParam());
                        String seqNo = Long.toString(Math.abs(new Random().nextLong()));
                        ResponseEntity<String> responseEntity = dexClient.text("edu", "20190515013", "1.0", seqNo, t.getParam());
                        String ebody = responseEntity.getBody();
                        log.info(DateUtils.getCurrentTime() + "job调用学责生成发票接口，回参" + ebody + "," + responseEntity.getStatusCodeValue());
                        Document doc = null;
                        doc = DocumentHelper.parseText(ebody);
                        Element ebodyElement = doc.getRootElement();
                        // 根据code 0000  判断 。也可以根据返回值data判断  成功有数据，失败为null
                        // String code = ebodyElement.element("code").getStringValue();
                        String code = ebodyElement.element("POLICY").attributeValue("RETURN");

                        if ("true".equals(code)) {
                            // 组装生成电子发票的报文
                            doc = DocumentHelper.createDocument();
                            Element info = doc.addElement("Message");
                            doc.setRootElement(info);
                            Element Body = info.addElement("Body");
                            // Element OrderNo = Body.addElement("OrderNo").addText(orderNo);
                            Element PolicyNO = Body.addElement("PolicyNO").addText(t.getPolicyNo());
                            t.setDownParam(info.asXML());
                            t.setStatus("6");
                            t.setTimes(times);
                            // 生成电子发票成功，更新数据库，
                            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                        } else {
                            log.error("请求生成电子发票失败");
                            t.setStatus("7");
                            t.setTimes(times);
                            // 生成电子发票失败，更新数据库，
                            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("请求生成电子发票失败");
                        t.setStatus("7");
                        t.setTimes(times);
                        // 生成电子发票失败，更新数据库，
                        issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                    }
                }
            }
        }
    }


    private List<IssuePolicyLogEntity> checkDownInvoice() {


        Weekend<IssuePolicyLogEntity> weekend = Weekend.of(IssuePolicyLogEntity.class);
        WeekendCriteria<IssuePolicyLogEntity, Object> criteria = weekend.weekendCriteria();
        criteria.andEqualTo(IssuePolicyLogEntity::getType, "3");
        criteria.andEqualTo(IssuePolicyLogEntity::getStatus, "6");
        criteria.andEqualTo(IssuePolicyLogEntity::getProCode, "19PR403423");//学责
        criteria.andIsNull("eInvoiceId");
        criteria.andBetween(IssuePolicyLogEntity::getTimes, minTimes, maxTimes);
        return jobQueryListService.getJobProcessIssuePolicyLogList(weekend);
    }

    /**
     * 实责校责下载电子发票
     *
     * @param issuePolicyLogEntities
     */
    private void downAndBindSZANDXZ(List<IssuePolicyLogEntity> issuePolicyLogEntities) {
        if (issuePolicyLogEntities != null && issuePolicyLogEntities.size() > 0) {
            for (IssuePolicyLogEntity t : issuePolicyLogEntities) {
                String desc = PolicyEnum.getIssueEnum(t.getIfCode()).getDesc();
                int times = t.getTimes() + 1;
                log.info(DateUtils.getCurrentTime() + "job调用" + desc + "下载发票的接口，入参" + t.getParam());
                String seqNo = Long.toString(Math.abs(new Random().nextLong()));
                ResponseEntity<String> responseEntity = null;
                try {
                    String invoice = PolicyEnum.getPolicyOrInvoiceByIfCode(t.getIfCode(), "INVOICE");
                    responseEntity = dexClient.text("edu", invoice, "1.0", seqNo, t.getParam());
                    log.info(DateUtils.getCurrentTime() + "job调用" + desc + "下载发票的接口，回参" + responseEntity.getStatusCodeValue() + "," + responseEntity.getBody());
                    if (StringUtil.isEmpty(responseEntity.getBody())) {
                        log.error("请求下载电子发票失败");
                        t.setStatus("6");
                        t.setTimes(times);
                        issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                    } else {
                        if (responseEntity.getStatusCodeValue() != 200) {
                            log.error("请求下载电子发票失败");
                            t.setStatus("6");
                            t.setTimes(times);
                            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                        } else {
                            String ebody = responseEntity.getBody();
                            Document doc = DocumentHelper.parseText(ebody);
                            Element ebodyElement = doc.getRootElement();
                            String code = ebodyElement.element("code").getStringValue();
                            if ("0000".equals(code)) {
                                String eInvoiceId = ebodyElement.element("data").getStringValue();
                                t.setStatus("2");
                                t.setEInvoiceId(eInvoiceId);
                                t.setTimes(times);
                                bindInvoice(t.getApplicationFormCode(), eInvoiceId, t);
                            } else {
                                t.setStatus("6");
                                t.setTimes(times);
                                issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("请求下载电子发票失败");
                    t.setStatus("6");
                    t.setTimes(times);
                    issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                }
            }
        }
    }

    private List<IssuePolicyLogEntity> checkDownSZANDXZInvoice() {
        // 实责校责  状态6  type3  Procode = 1 或者 2 ；maintype 1或 2
        Weekend<IssuePolicyLogEntity> weekend = Weekend.of(IssuePolicyLogEntity.class);
        WeekendCriteria<IssuePolicyLogEntity, Object> criteria = weekend.weekendCriteria();
        criteria.andEqualTo(IssuePolicyLogEntity::getType, "3");
        criteria.andEqualTo(IssuePolicyLogEntity::getStatus, "6");
        List<String> procodeList = new ArrayList<String>();
        procodeList.add("19PR789827");//.add("1");// 全国职业院校学生实习责任保险
        procodeList.add("19PR961660");//.add("2");// 校方责任保险
        criteria.andIn(IssuePolicyLogEntity::getProCode, procodeList);
        criteria.andIsNull("eInvoiceId");
        criteria.andBetween(IssuePolicyLogEntity::getTimes, minTimes, maxTimes);
        return jobQueryListService.getJobProcessIssuePolicyLogList(weekend);
    }


    private List<IssuePolicyLogEntity> checkDownYNFJInvoice() {
        Weekend<IssuePolicyLogEntity> weekend = Weekend.of(IssuePolicyLogEntity.class);
        WeekendCriteria<IssuePolicyLogEntity, Object> criteria = weekend.weekendCriteria();
        criteria.andEqualTo(IssuePolicyLogEntity::getType, "3");
        criteria.andEqualTo(IssuePolicyLogEntity::getStatus, "6");
        List<String> productList = new ArrayList<String>();
        productList.add("19PR452292");//.add("40000");//校方综合防范保障保险
        productList.add("19PR467834");//.add("30000");//教职员工校方责任保险
        productList.add("19PR233356");//.add("20000");//校园食品安全责任保险
        productList.add("19PR534934");//.add("10000");//云南省校方责任保险
        criteria.andIsNull("eInvoiceId");
        criteria.andBetween(IssuePolicyLogEntity::getTimes, minTimes, maxTimes);
        criteria.andIn(IssuePolicyLogEntity::getProCode, productList);
        return jobQueryListService.getJobProcessIssuePolicyLogList(weekend);
    }


    private void createInvoice(List<IssuePolicyLogEntity> issuePolicyLogEntities) {
        if (issuePolicyLogEntities != null && issuePolicyLogEntities.size() > 0) {

            for (IssuePolicyLogEntity t : issuePolicyLogEntities) {
                int times = t.getTimes() + 1;
                // 云南非九4个险种  需要生成发票
                String proCode = t.getProCode();
                if ("19PR452292".equals(proCode) || "19PR467834".equals(proCode)
                        || "19PR233356".equals(proCode) || "19PR534934".equals(proCode)) {
                    try {
                        log.info(DateUtils.getCurrentTime() + "job调用云南非九生成发票接口，入参" + t.getParam());
                        String seqNo = Long.toString(Math.abs(new Random().nextLong()));
                        ResponseEntity<String> responseEntity = dexClient.text("edu", "20190516026", "1.0", seqNo, t.getParam());
                        String consumeStatus = "6";
                        String ebody = responseEntity.getBody();
                        log.info(DateUtils.getCurrentTime() + "job调用云南非九生成发票接口，回参" + ebody + "," + responseEntity.getStatusCodeValue());
                        Document doc = DocumentHelper.parseText(ebody);
                        Element ebodyElement = doc.getRootElement();
                        Element body = ebodyElement.element("body");
                        Element head = ebodyElement.element("head");
                        String msg = null;
                        Element downData = null;
                        if (body != null) {// 说明请求成功  返回发票url
                            String url = body.element("url").getStringValue();
                            msg = head.element("msg").getStringValue();
                            if (StringUtil.isEmpty(url)) {
                                log.error("{} 请求生成电子发票失败", t.getApplicationFormCode());
                                consumeStatus = "7";
                                t.setStatus(consumeStatus);
                                t.setUpdateTime(DateUtils.getCurrentTime());
                                t.setResponseMsg(msg);
                                t.setTimes(times);
                                // 生成电子发票失败，更新数据库，
                                issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                            } else {
                                // 组装生成电子发票的报文
                                doc = DocumentHelper.createDocument();
                                Element info = doc.addElement("Body");
                                Element Body = info.addElement("url");
                                Body.addText(url);
                                t.setDownParam(info.asXML());
                                t.setStatus(consumeStatus);
                                t.setUpdateTime(DateUtils.getCurrentTime());
                                t.setTimes(times);
                                // 生成电子发票成功，更新数据库，
                                issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                            }
                        } else {
                            log.error(" {} 请求生成电子发票失败", t.getApplicationFormCode());
                            t.setTimes(times);
                            consumeStatus = "7";
                            t.setResponseMsg(msg);
                            t.setUpdateTime(DateUtils.getCurrentTime());
                            t.setStatus(consumeStatus);
                            // 生成电子发票失败，更新数据库，
                            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error(" {} 请求生成电子发票失败", t.getApplicationFormCode());
                        t.setTimes(times);
                        t.setStatus("7");
                        t.setUpdateTime(DateUtils.getCurrentTime());
                        // 生成电子发票失败，更新数据库，
                        issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                    }
                }
            }
        }
    }

    /**
     * 云南非九下载电子发票
     *
     * @param issuePolicyLogEntities
     */
    private void downAndBindYNFJ(List<IssuePolicyLogEntity> issuePolicyLogEntities) {

        if (issuePolicyLogEntities != null && issuePolicyLogEntities.size() > 0) {
            for (IssuePolicyLogEntity t : issuePolicyLogEntities) {
                int times = t.getTimes() + 1;
                log.info(DateUtils.getCurrentTime() + "job调用云南非九下载发票的接口，入参" + t.getDownParam());
                String seqNo = Long.toString(Math.abs(new Random().nextLong()));
                ResponseEntity<String> responseEntity = null;
                try {
                    responseEntity = dexClient.text("edu", "20190516036", "1.0", seqNo, t.getDownParam());
                    log.info(DateUtils.getCurrentTime() + "job调用云南非九下载发票的接口，回参" + responseEntity.getStatusCodeValue() + "," + responseEntity.getBody());
                    // 请求200，继续执行
                    if (responseEntity.getStatusCodeValue() != 200) {
                        log.error("请求下载电子发票失败");
                        t.setStatus("6");
                        t.setTimes(times);
                        t.setUpdateTime(DateUtils.getCurrentTime());
                        issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                    } else {
                        String ebody = responseEntity.getBody();
                        Document doc = DocumentHelper.parseText(ebody);
                        Element ebodyElement = doc.getRootElement();
                        String code = ebodyElement.element("code").getStringValue();
                        if ("0000".equals(code)) {
                            String eInvoiceId = ebodyElement.element("data").getStringValue();
                            t.setStatus("2");
                            t.setEInvoiceId(eInvoiceId);
                            t.setTimes(times);
                            t.setUpdateTime(DateUtils.getCurrentTime());
                            bindInvoice(t.getApplicationFormCode(), eInvoiceId, t);
                        } else {
                            t.setStatus("6");
                            t.setTimes(times);
                            t.setUpdateTime(DateUtils.getCurrentTime());
                            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("请求下载电子发票失败");
                    t.setStatus("6");
                    t.setTimes(times);
                    t.setUpdateTime(DateUtils.getCurrentTime());
                    issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                }
            }
        }
    }

    /**
     * 查询失败最大次数的电子发票 t_issue_policy_log.status >6
     *
     * @return
     */
    private List<IssuePolicyLogEntity> queryFailInvoice() {
        Weekend<IssuePolicyLogEntity> weekend = Weekend.of(IssuePolicyLogEntity.class);
        WeekendCriteria<IssuePolicyLogEntity, Object> criteria = weekend.weekendCriteria();
        List<String> statusList = new ArrayList<String>();
        statusList.add("1");
        statusList.add("7");
        criteria.andIn(IssuePolicyLogEntity::getStatus, statusList);
        criteria.andEqualTo(IssuePolicyLogEntity::getType, "3");
        criteria.andBetween(IssuePolicyLogEntity::getTimes, minTimes, maxTimes);
        criteria.andIsNull("eInvoiceId");
        return jobQueryListService.getJobProcessIssuePolicyLogList(weekend);
    }

    private void bindInvoice(String applicationFormCode, String fileId, IssuePolicyLogEntity issuePolicyLogEntity) throws Exception {
        String status = issuePolicyLogEntity.getStatus();
        ResBindQo resBindQo = new ResBindQo();
        resBindQo.setApplicationFormCode(applicationFormCode);
        ResBindDetailQo resBindDetailQo = new ResBindDetailQo();
        resBindDetailQo.setBizCodeType("02");
        resBindDetailQo.setResCode("P001");
        resBindDetailQo.setResId(fileId);
        resBindDetailQo.setResName("电子发票");
        List<ResBindDetailQo> list = new ArrayList<>();
        list.add(resBindDetailQo);
        resBindQo.setDetailList(list);
        ResponseEntity<GenericListResponse<Map<String, String>>> genericListResponseResponseEntity = null;
        genericListResponseResponseEntity = insClient.bindResources(resBindQo);
        GenericListResponse<Map<String, String>> body = genericListResponseResponseEntity.getBody();
        String code = body.getCode();
        log.info(DateUtils.getCurrentTime() + "调用绑定资源接口返回结果码" + code + ":" + body.getMsg());
        if (!"0000".equals(code)) {
            issuePolicyLogEntity.setEPolicyId(fileId);
            issuePolicyLogEntity.setStatus("6");
            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(issuePolicyLogEntity);
        } else {
            issuePolicyLogEntity.setEPolicyId(fileId);
            issuePolicyLogEntity.setStatus("2");
            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(issuePolicyLogEntity);
        }
    }
}
